package com.jcn.seckill.redis;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;

//将自动注册到Spring容器，不需要再在applicationContext.xml文件定义bean了
@Service
public class RedisService {
	
	//对类成员变量、方法及构造函数进行标注，完成自动装配的工作
	//@Autowired标注可以放在成员变量上，也可以放在成员变量的set方法上，也可以放在任意方法上表示
	@Autowired
	//注入接口
	//注入JedisPool，获取jedis对象
	JedisPool jedisPool;
	
	/**
	 * 获取单个对象
	 * 通过jedisPool获取jedis对象,然后进行get,set操作
	 * */
	public <T> T get(KeyPrefix prefix, String key,  Class<T> clazz) {
		 Jedis jedis = null;
		 try {
			 //连接池用完想要释放掉，所以使用try{}
			 //通过jedisPool获取jedis对象来实现get和set
			 jedis =  jedisPool.getResource();
			//生成真正的key，getPrefix先拿到类名再拼一个key
			 String realKey  = prefix.getPrefix() + key;
			 String str = jedis.get(realKey);
			 //将string转化为bean输出出去
			 T t =  stringToBean(str, clazz);
			 return t;
		 }finally {
			  //释放掉连接池
			  returnToPool(jedis);
		 }
	}
	
	/**
	 * 设置对象
	 * */
	public <T> boolean set(KeyPrefix prefix, String key,  T value) {
		 Jedis jedis = null;
		 try {
			 jedis =  jedisPool.getResource();
			 //set操作需要将类型转化为string
			 String str = beanToString(value);
			 if(str == null || str.length() <= 0) {
				 return false;
			 }
			 //生成真正的key
			 String realKey  = prefix.getPrefix() + key;
			 //过期时间
			 int seconds =  prefix.expireSeconds();
			 //如果小于0，则是永不过期的，调用set，否则调用setex：先设置一个值，然后设置一个过期时间
			 if(seconds <= 0) {
				 jedis.set(realKey, str);
			 }else {
				 jedis.setex(realKey, seconds, str);
			 }
			 return true;
		 }finally {
			  returnToPool(jedis);
		 }
	}
	
	/**
	 * 判断key是否存在
	 * */
	public <T> boolean exists(KeyPrefix prefix, String key) {
		 Jedis jedis = null;
		 try {
			 jedis =  jedisPool.getResource();
			//生成真正的key
			 String realKey  = prefix.getPrefix() + key;
			return  jedis.exists(realKey);
		 }finally {
			  returnToPool(jedis);
		 }
	}
	
	/**
	 * 删除
	 * */
	public boolean delete(KeyPrefix prefix, String key) {
		 Jedis jedis = null;
		 try {
			 jedis =  jedisPool.getResource();
			//生成真正的key
			String realKey  = prefix.getPrefix() + key;
			//返回long类型数据
			long ret =  jedis.del(realKey);
			return ret > 0;
		 }finally {
			  returnToPool(jedis);
		 }
	}
	
	/**
	 * 增加值
	 * */
	public <T> Long incr(KeyPrefix prefix, String key) {
		 Jedis jedis = null;
		 try {
			 jedis =  jedisPool.getResource();
			//生成真正的key
			 String realKey  = prefix.getPrefix() + key;
			return  jedis.incr(realKey);
		 }finally {
			  returnToPool(jedis);
		 }
	}
	
	/**
	 * 减少值
	 * */
	public <T> Long decr(KeyPrefix prefix, String key) {
		 Jedis jedis = null;
		 try {
			 jedis =  jedisPool.getResource();
			 //生成真正的key
			 String realKey  = prefix.getPrefix() + key;
			 //decr：如果key存在则或者错误，则将key设置为0，如果是string类型的操作，则返回-1
			 //如果是正常的key，则减一，再输出出来，原子操作，不可分
			 return  jedis.decr(realKey);
		 }finally {
			  returnToPool(jedis);
		 }
	}
	
	public boolean delete(KeyPrefix prefix) {
		if(prefix == null) {
			return false;
		}
		List<String> keys = scanKeys(prefix.getPrefix());
		if(keys==null || keys.size() <= 0) {
			return true;
		}
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			jedis.del(keys.toArray(new String[0]));
			return true;
		} catch (final Exception e) {
			e.printStackTrace();
			return false;
		} finally {
			if(jedis != null) {
				jedis.close();
			}
		}
	}
	
	public List<String> scanKeys(String key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			List<String> keys = new ArrayList<String>();
			String cursor = "0";
			ScanParams sp = new ScanParams();
			sp.match("*"+key+"*");
			sp.count(100);
			do{
				ScanResult<String> ret = jedis.scan(cursor, sp);
				List<String> result = ret.getResult();
				if(result!=null && result.size() > 0){
					keys.addAll(result);
				}
				//再处理cursor
				cursor = ret.getStringCursor();
			}while(!cursor.equals("0"));
			return keys;
		} finally {
			if (jedis != null) {
				jedis.close();
			}
		}
	}
	//将任意类型转化为字符串
	public static <T> String beanToString(T value) {
		if(value == null) {
			return null;
		}
		Class<?> clazz = value.getClass();
		//如果是int，long型，则直接写入，否则进行转型
		if(clazz == int.class || clazz == Integer.class) {
			 return ""+value;
		}else if(clazz == String.class) {
			 return (String)value;
		}else if(clazz == long.class || clazz == Long.class) {
			return ""+value;
		}else {
			//将bean对象转换为json字符串
			return JSON.toJSONString(value);
		}
	}

	//压制警告
	@SuppressWarnings("unchecked")
	//把字符串转化为bean对象
	public static <T> T stringToBean(String str, Class<T> clazz) {
		if(str == null || str.length() <= 0 || clazz == null) {
			 return null;
		}
		if(clazz == int.class || clazz == Integer.class) {
			 return (T)Integer.valueOf(str);
		}else if(clazz == String.class) {
			 return (T)str;
		}else if(clazz == long.class || clazz == Long.class) {
			return  (T)Long.valueOf(str);
		}else {
			//parseObject：将json字符串转换为bean对象
			return JSON.toJavaObject(JSON.parseObject(str), clazz);
		}
	}

	private void returnToPool(Jedis jedis) {
		 //如果jedis不为空，则close掉，实际上并没有关闭，只是把他返回到连接池里面
		 if(jedis != null) {
			 jedis.close();
		 }
	}

}
